﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Abp.Dependency;
using Abp.Web.Api.Modeling;
using Abp.Web.Api.ProxyScripting.Generators;

namespace Xugege.AbpExtension.Web.Core.Extension.Controllers.Scripts.Angular
{
    public class Angular2ProxyGenerator : IProxyScriptGenerator, ITransientDependency
    {


        public const string Name = "ng2";
        public string CreateScript(ApplicationApiDescriptionModel model)
        {
            var script = new StringBuilder();

            script.AppendLine("import * as moment from 'moment';");
            script.AppendLine("import 'rxjs/Rx';");
            script.AppendLine("import { Observable } from 'rxjs/Observable';");
            script.AppendLine("import { Injectable, Inject, Optional, OpaqueToken } from '@angular/core';");
            script.AppendLine("import { Http, Headers, Response, RequestOptionsArgs } from '@angular/http';");
            script.AppendLine("import { ExceptionHandler, ResponseHandler, NameValueDto, ResponseBody } from './service-proxies.common';");
            script.AppendLine("import { AppConsts } from '@shared/AppConsts';");

            foreach (var module in model.Modules.Values)
            {
                //string moduleName = module.Name;
                CreateController(script, module);
            }

            return script.ToString();
        }

        private void CreateController(StringBuilder script, ModuleApiDescriptionModel module)
        {

            script.AppendLine("                    ");
            script.AppendLine("                    ");
            foreach (var ctrl in module.Controllers.Values)
            {

                script.AppendLine("@Injectable()");
                script.AppendLine($"export class { ToUpperFirst(ctrl.Name)}ServiceProxy " + @"{");
                CreateConstructor(script);
                script.AppendLine("");

                foreach (var action in ctrl.Actions.Values)
                {
                    CreateActions(script, module, ctrl, action);
                }

                script.AppendLine(@"}");
            }
            script.AppendLine("                    ");
            script.AppendLine("                    ");

        }

        private void CreateActions(StringBuilder script, ModuleApiDescriptionModel module,
            ControllerApiDescriptionModel controller, ActionApiDescriptionModel action)
        {
            var httpMethod = action.HttpMethod?.ToUpperInvariant() ?? "POST";
            script.AppendLine("");
            #region 方法开始

            //ProxyScriptingHelperExtesion.GetInputDtoFromAction(action, ToUpperFirst(action.Name));

            if (action.Parameters.Any())
                script.AppendLine($"    {ToLowerFirst(action.Name)}(input:any):Observable<any> " + @"{");
            else script.AppendLine($"    {ToLowerFirst(action.Name)}():Observable<any> " + @"{");

            if (httpMethod.ToLower() == "get")
                script.AppendLine("        let _url = this.baseUrl +'/" +
                                  ProxyScriptingHelperExtesion.GenerateUrlWithParameters(action) + "'");
            else
                script.AppendLine("        let _url = this.baseUrl +'/" + action.Url + "'");

            script.AppendLine(httpMethod.ToLower() == "get"
                ? @"        let _content = ''"
                : @"        let _content = input !== undefined ? JSON.stringify(input) : null;");

            script.AppendLine("        return this.http.request(_url, {");
            script.AppendLine("            body: _content,");
            script.AppendLine($"            method: '{httpMethod.ToLower()}',");

            if (httpMethod.ToLower() == "post")
            {
                script.AppendLine("            headers: new Headers({");
                script.AppendLine("            'Content-Type': 'application/json; charset=UTF-8'");
                script.AppendLine("            })");
            }
            script.AppendLine("        }).map(response => {");
            script.AppendLine($"            return this.process{ToUpperFirst(action.Name)}(response);");
            script.AppendLine("        }).catch((response: any, caight: any) => {");
            script.AppendLine($"            return ExceptionHandler.handler<any>(response, this.process{ToUpperFirst(action.Name)}(response));");
            script.AppendLine("        });");

            script.AppendLine(@"    }");
            #endregion 方法结束

            #region 响应处理
            script.AppendLine($@"     protected process{ToUpperFirst(action.Name)}(response: Response): any " + "{");
            script.AppendLine("            return ResponseHandler.process<any>(response, (result) => {");
            script.AppendLine("                return result;");
            script.AppendLine("            });");
            script.AppendLine("       }");
            #endregion
        }

        private static void CreateConstructor(StringBuilder script)
        {
            script.AppendLine(@"    private baseUrl: string = undefined;");
            script.AppendLine(
                @"    constructor( @Inject(Http) private http: Http) {");
            script.AppendLine(@"        this.baseUrl = AppConsts.remoteServiceBaseUrl;");
            script.AppendLine(@"    }");
        }

        private string ToLowerFirst(string source)
        {
            return source.Substring(0, 1).ToLower() + source.Substring(1, source.Length - 1);
        }

        private string ToUpperFirst(string source)
        {
            return source.Substring(0, 1).ToUpper() + source.Substring(1, source.Length - 1);
        }
    }
}
